package com.hxw.sample.opengl30;

import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;

import com.hxw.sample.opengl30.uitls.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;

/**
 * 实现VAO
 * VAO可以实现对VBO的管理，不用每次都切换选择VBO
 */
public class TriangleRenderV5_VAO implements GLSurfaceView.Renderer {

    //顶点绘制脚本
    private static final String vertex_shader = "attribute vec4 vPosition;\n" +//顶点坐标，我们需要在Java获取到这个值并赋值
            "void main() {\n" +
            "  gl_Position = vPosition;\n" +//gl_Position是OpenGL内部变量，OpenGL通过该值获取顶点位置
            "}";

    //纹理绘制脚本（在顶点的基础上，加上颜色或图像就是纹理）
    private static final String fragment_shader = "precision mediump float;//浮点数精度\n" +
            "uniform vec4 vColor;\n" +//纹理颜色,uniform的意思是全局变量，仅当为uniform类型时，才能在Java获取片元中变量并赋值
            "void main() {\n" +
            "    gl_FragColor = vColor;\n" +//gl_FragColor是OpenGL内部变量，OpenGL通过该值获取像素点的纹理
            "}";

    //一个顶点通常用x,y,z这三个值来表示，但如果是二维，则z可有可无，为0即可
    private final float[] VERTEX ={
            -1f, 0f ,0f,//v1
            0f, -1f ,0f,//v2
            0f, 1f ,0f, //v3
    };
    private FloatBuffer mVertexBuffer;

    private final float[] COLOR = {0.5f,0.5f,0.5f,1.0f};//纹理颜色通常用4个值对应，分别为：R,G,B,A

    private int mProgram,mPositionHandle,mColorHandle;

    private final int[] vboIds = new int[1];//VBO
    private final int[] vaoIds = new int[1];//VAO

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        final int byteLen = VERTEX.length*4;//字节长度,float占4个字节，所以乘以4
        mVertexBuffer = ByteBuffer.allocateDirect(byteLen)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(VERTEX);
        mVertexBuffer.position(0);

        //程序必须在onSurfaceCreated之后加载才行，否则OpenGL环境未就绪是无法正常加载的
        mProgram = ShaderUtil.createProgram(vertex_shader,fragment_shader);

        if (mProgram != 0){
            mPositionHandle = GLES30.glGetAttribLocation(mProgram,"vPosition");//获取顶点脚本中的vPosition变量的句柄
            mColorHandle = GLES30.glGetUniformLocation(mProgram,"vColor");//获取纹理脚本中的vColor变量的句柄

            GLES30.glGenVertexArrays(1,vaoIds,0);//第一个参数为需要创建的VAO数量，第三个参数为0
            GLES30.glBindVertexArray(vaoIds[0]);//绑定VAO,后续VBO会被自动加入VAO中

            GLES30.glGenBuffers(1,vboIds,0);//第一个参数为需要创建的VBO数量，第三个参数为0
            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,vboIds[0]);//绑定VBO
            GLES30.glBufferData(GLES20.GL_ARRAY_BUFFER,byteLen,mVertexBuffer,GLES30.GL_STATIC_DRAW);//将数据写入VBO

            GLES30.glEnableVertexAttribArray(mPositionHandle);//设置顶点参数为可用
            GLES30.glVertexAttribPointer(mPositionHandle, 3, GLES30.GL_FLOAT, false, 12, 0);//从VBO中取值并赋值
            //glVertexAttribPointer的执行，会被记录到VAO中，后续就只需要从VAO中取即可

            GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER,0);//解绑VBO
            GLES30.glBindVertexArray(0);//解绑VAO

        }

        GLES30.glClearColor(1,0,0,1f);//设置清空View时的背景色
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0,0,width,height);//绘制的区间
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);//清除颜色缓冲区

        GLES30.glUseProgram(mProgram);//指定当前渲染操作所要使用的着色器程序

        GLES30.glBindVertexArray(vaoIds[0]);//绑定VAO

        GLES30.glUniform4fv(mColorHandle, 1,COLOR,0);//设置纹理颜色为红色

        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP,0, 3);//渲染，第三个参数为顶点数量

        GLES30.glBindVertexArray(0);//解绑VAO
    }

    public void onDestroy(){
        GLES30.glDeleteBuffers(1,vboIds,0);
        GLES30.glDeleteBuffers(1,vaoIds,0);

        GLES30.glDeleteProgram(mProgram);
    }
}
